//******************************************************************************
//this code is protected by the GNU affero GPLv3
//author:Sylvain BERTRAND <sylvain.bertrand AT gmail dot com>
//                        <digital.ragnarok AT gmail dot com>
//******************************************************************************
#include "globals.h"

//public because of the default seat
s8 seat_bind_post(struct client *c,s32 name,u32 id)
{
  return wl_seat_ev_capabilities(c,id,registry[name].seat.caps);
}

s32 seat_new(u8 *id_seat)
{
  s32 seat_name=0;
  while(1){
    if(seat_name==REGISTRY_N_MAX) return LWL_ERR;
    if(registry[seat_name].itf==WL_INVALID) break;
    ++seat_name;
  }

  registry[seat_name].itf=WL_SEAT;
  registry[seat_name].n=0;
  registry[seat_name].is_singleton=0;
  registry[seat_name].release=registry_gbl_generic_release;
  registry[seat_name].bind_post=seat_bind_post;

  strncpy(&registry[seat_name].seat.id[0],id_seat,FREEDESKTOP_SEAT_ID_SZ);
  registry[seat_name].seat.caps=0;
  return seat_name;
}

s8 seat_get_pointer(struct client *c,s32 seat_name,u32 pointer_id)
{
  s8 r=pointer_new_visible(c,pointer_id,seat_name);
  if(r==LWL_ERR)
    PERR("client(%d):seat::get_pointer unable to create new pointer\n",c->so);
  return r;
}

s8 seat_get_keyboard(struct client *c,s32 seat_name,u32 keyboard_id)
{
  s8 r=keyboard_new_visible(c,keyboard_id,seat_name);
  if(r==LWL_ERR)
    PERR("client(%d):seat::get_keyboard unable to create new keyboard\n",c->so);
  return r;
}

#define SEAT_CAPS_SAME    0
#define SEAT_CAPS_CHANGED 1
static s8 seat_reconfigure(s32 seat_name)
{
  u32 old_caps=registry[seat_name].seat.caps;
  u32 new_caps=0;

  s8 evdev=0;
  while(1){
    if(evdev==LINUX_EVDEVS_MAX) break;
    if(evdevs[evdev].fd!=-1&&evdevs[evdev].seat_name==seat_name){
      if(lwl_evdev_has_pointer(&evdevs[evdev]))
        new_caps|=WL_SEAT_CAPABILITY_POINTER;
      if(lwl_evdev_has_keyboard(&evdevs[evdev]))
        new_caps|=WL_SEAT_CAPABILITY_KEYBOARD;
    }
    ++evdev;
  }

  s8 r=SEAT_CAPS_SAME;
  if(old_caps!=new_caps){
    r=SEAT_CAPS_CHANGED;
    registry[seat_name].seat.caps=new_caps;
  }
  return r;
}

static void seat_caps_broadcast(s32 seat_name)
{
  s32 client=0;
  while(1){
    if(client==CLIENTS_MAX) break;
    struct client *c=&clients[client];
    s32 obj=CLIENT_FIRST_VALID_ID;
    while(1){
      if(obj==CLIENT_OBJS_MAX) break;
      struct client_obj *o=&c->objs[obj];
      if(!(o->state&CLIENT_OBJ_INVALID)&&(o->state&CLIENT_OBJ_REGISTRY_MAP)){
        struct gbl *g=&registry[o->map.name];
        if(g->itf==WL_SEAT&&o->map.name==seat_name){
          s8 r=wl_seat_ev_capabilities(c,o->id,g->seat.caps);
          if(r==LWL_ERR) client_kill(c);//punish misbehaving client
        }
      }
      ++obj;
    }
    ++client;
  }
}

void seat_input_change(s32 seat_name)
{
  s8 r=seat_reconfigure(seat_name);
  if(r==SEAT_CAPS_CHANGED) seat_caps_broadcast(seat_name);
}
